package cz.muni.fi.pa165.sme.dao.impl;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
import javax.persistence.TypedQuery;

import cz.muni.fi.pa165.sme.dao.api.SportActivityRecordDao;
import cz.muni.fi.pa165.sme.dao.entity.SportActivity;
import cz.muni.fi.pa165.sme.dao.entity.SportActivityRecord;
import cz.muni.fi.pa165.sme.dao.entity.User;
import cz.muni.fi.pa165.sme.dao.exception.DataStorageOperationException;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import static cz.muni.fi.pa165.sme.common.EntityValidator.validateDeleteEntity;
import static cz.muni.fi.pa165.sme.common.EntityValidator.validateEntityManager;
import static cz.muni.fi.pa165.sme.common.EntityValidator.validateGetEntity;
import static cz.muni.fi.pa165.sme.common.EntityValidator.validateNewEntity;
import static cz.muni.fi.pa165.sme.common.EntityValidator.validateUpdatedEntity;

/**
 *
 * @author jirankova
 */
@Repository
public class SportActivityRecordDaoImpl implements SportActivityRecordDao {

	@PersistenceContext
	private EntityManager entityManager;

	public void setEntityManager(EntityManager entityManager) {
		this.entityManager = entityManager;
	}

	@Override
	@Transactional
	public void createSportActivityRecord(final SportActivityRecord sportActivityRecord) {
		validateEntityManager(entityManager);
		validateNewEntity(sportActivityRecord);

		try{
			entityManager.persist(sportActivityRecord);
		}catch (PersistenceException e){
			throw new DataStorageOperationException("An error has occurred while inserting a new sport activity record " +
					"object to the database",e);
		}
	}

	@Override
    @Transactional
	public void deleteSportActivityRecord(final SportActivityRecord sportActivityRecord) {
		validateEntityManager(entityManager);
        validateDeleteEntity(sportActivityRecord);

		try{
            SportActivityRecord foundActivityRecord = entityManager.find(SportActivityRecord.class, sportActivityRecord.getId());
            entityManager.remove(foundActivityRecord);
		}catch (PersistenceException e){
			throw new DataStorageOperationException("An error has occurred while deleting Sport activity record from " +
					"the database",e);
		} catch (IllegalArgumentException e){
			throw new DataStorageOperationException("Sport activity record: " + sportActivityRecord + " does not exist " +
					"in the database, or the argument is invalid",e);
		}
	}

	@Override
    @Transactional
	public void updateSportActivityRecord(final SportActivityRecord sportActivityRecord) {
		validateEntityManager(entityManager);
		validateUpdatedEntity(sportActivityRecord);

		try{
			final SportActivityRecord oldRecord = entityManager.find(SportActivityRecord.class, sportActivityRecord.getId());
			if(oldRecord == null) {
				throw new IllegalArgumentException("Entity cannot be updated if it does not exist.");
			}

			entityManager.merge(sportActivityRecord);
		} catch (PersistenceException e){
			throw new DataStorageOperationException("An error has occurred while updating Sport activity record in database",e);
		} catch (IllegalArgumentException e){
			throw new DataStorageOperationException("Sport activity record: " + sportActivityRecord + "does not exist in the database," +
					" or the argument is wrong",e);
		}
	}

	@Override
	public SportActivityRecord findSportActivityRecordById(final Long id) {
		validateGetEntity(id);
		validateEntityManager(entityManager);

		try{
			return entityManager.find(SportActivityRecord.class, id);
		} catch (PersistenceException ex) {
			throw new DataStorageOperationException("An error has occured when looking for a sport activity record in database.", ex);
		}
	}

	@Override
	public List<SportActivityRecord> findAllSportActivityRecordsByUser(final User user) {
		if(user == null) {
			throw new IllegalArgumentException("User to be looked up cannot be null");
		}

		validateEntityManager(entityManager);

		try{
			TypedQuery<SportActivityRecord> selectByUser = entityManager.createNamedQuery(SportActivityRecord.SELECT_BY_USER, SportActivityRecord.class);
			selectByUser.setParameter("userId", user.getId());
			return selectByUser.getResultList();
		} catch (PersistenceException ex) {
			throw new DataStorageOperationException("An error has occured when looking for a sport activity record in database.", ex);
		}
	}

    @Override
    public List<SportActivityRecord> findAllSportActivityRecordsBySportActivity(SportActivity sportActivity) {
		if(sportActivity == null) {
			throw new IllegalArgumentException("Sport activity to be looked up cannot be null");
		}

		validateEntityManager(entityManager);

		try{
			TypedQuery<SportActivityRecord> selectByUser = entityManager.createNamedQuery(SportActivityRecord.SELECT_BY_SPORT_ACTIVITY, SportActivityRecord.class);
			selectByUser.setParameter("sportId", sportActivity.getId());
			return selectByUser.getResultList();
		} catch (PersistenceException ex) {
			throw new DataStorageOperationException("An error has occured when looking for a sport activity record in database.", ex);
		}
	}

	@Override
	public List<SportActivityRecord> findAllSportActivityRecords() {
		validateEntityManager(entityManager);

		try{
			TypedQuery<SportActivityRecord> selectByUser = entityManager.createNamedQuery(SportActivityRecord.SELECT_ALL, SportActivityRecord.class);
			return selectByUser.getResultList();
		} catch (PersistenceException ex) {
			throw new DataStorageOperationException("An error has occured when looking for a sport activity record in database.", ex);
		}
	}
}
